package com.itheima.stock.service.impl;

import com.google.common.collect.Lists;
import com.itheima.stock.config.StockInfoConfig;
import com.itheima.stock.mapper.StockBlockRtInfoMapper;
import com.itheima.stock.mapper.StockBusinessMapper;
import com.itheima.stock.mapper.StockMarketIndexInfoMapper;
import com.itheima.stock.mapper.StockRtInfoMapper;
import com.itheima.stock.pojo.StockBlockRtInfo;
import com.itheima.stock.pojo.StockMarketIndexInfo;
import com.itheima.stock.pojo.StockRtInfo;
import com.itheima.stock.service.StockTimerTaskService;
import com.itheima.stock.utils.DateTimeUtil;
import com.itheima.stock.utils.IdWorker;
import com.itheima.stock.utils.ParseType;
import com.itheima.stock.utils.ParserStockInfoUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.util.Strings;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@Service
@Slf4j
public class StockTimerTaskServiceImpl implements StockTimerTaskService {
    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private StockInfoConfig stockInfoConfig;

    @Autowired
    private IdWorker idWorker;

    @Autowired
    StockMarketIndexInfoMapper stockMarketIndexInfoMapper;

    @Autowired
    private ParserStockInfoUtil parserStockInfoUtil;

    @Autowired
    private StockBusinessMapper stockBusinessMapper;

    @Autowired
    private StockRtInfoMapper stockRtInfoMapper;
    @Autowired
    private StockBlockRtInfoMapper stockBlockRtInfoMapper;
    /*
        注入线程池对象
     */
    @Autowired
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;

    /**
     * 获取国内大盘的实时数据信息
     */
    @Override
    public void getInnerMarketInfo() {
        // 1 组装动态url 类似这种格式:::http://hq.sinajs.cn/list=s_sh000001,s_sz399001
        String url = stockInfoConfig.getMarketUrl() + String.join(",", stockInfoConfig.getInner());
        // 2 设置请求头信息
        HttpHeaders headers = new HttpHeaders();
        headers.add("Referer", "https://finance.sina.com.cn/stock/");
        // 下面这一行 可以不写
        //headers.add("User-Agent","Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36");
        // 组装请求对象
        HttpEntity<Object> entity = new HttpEntity<>(headers);
        // 3 发起请求
        String result = restTemplate.postForObject(url, entity, String.class);
        String reg = "var hq_str_(.+)=\"(.+)\";";
        Pattern pattern = Pattern.compile(reg);
        // 将查询结果中匹配正则表达式的部分筛选出来
        Matcher matcher = pattern.matcher(result);
        // 4 收集大盘封装后的对象
        ArrayList<StockMarketIndexInfo> list = new ArrayList<>();
        // 5 对正则筛选的对象进行操作
        while (matcher.find()) {
            // 获取大盘的id
            String marketCode = matcher.group(1);
            // 其它信息 "xxxx" 其实就是保存的股票的所有信息 组成的字符串
            String other = matcher.group(2);
            String[] others = other.split(",");
            // 大盘名称
            String marketName = others[0];
            // 当前点
            BigDecimal curPoint = new BigDecimal(others[1]);
            // 涨跌值
            BigDecimal curPrice = new BigDecimal(others[2]);
            // 涨跌率
            BigDecimal upDownRate = new BigDecimal(others[3]);
            // 成交量
            Long tradeAmount = Long.valueOf(others[4]);
            // 成交金额
            Long tradeVol = Long.valueOf(others[5]);
            // 当前日期
            Date now = DateTimeUtil.getDateTimeWithoutSecond(DateTime.now()).toDate();
            // 封装数据
            StockMarketIndexInfo build = StockMarketIndexInfo.builder().id(idWorker.nextId() + "")
                    .markName(marketName)
                    .tradeVolume(tradeVol)
                    .tradeAccount(tradeAmount)
                    .updownRate(upDownRate)
                    .curTime(now)
                    .curPoint(curPoint)
                    .currentPrice(curPrice)
                    .markId(marketCode)
                    .build();
            list.add(build);
        }
        log.info("集合内容：{}", list);//{} 是占位符
        //批量插入功能
        // 调用mapper层的方法
        stockMarketIndexInfoMapper.insertBatch(list);
    }

    /**
     * 定义获取分钟级股票数据
     * 根据股票的code去查询相应数据并插入到表格中
     */
    @Override
    public void getStockRtIndex() {
        // 1 获取到需要查询的股票的code
        List<String> stockIds = stockBusinessMapper.getStockIds();
        /*
           2 根据第三方接口路径的格式:::https://hq.sinajs.cn/list=sh601003,sh601001,sh601006
           将上述获取的code进行匹配 然后修改成"sh601001"这种格式
           最后将修改号的code存储到list集合中
        */
        List<String> newStockIds = stockIds.stream().map(id -> {
            if (id.startsWith("6")) {
                //id += "sh";
                id = "sh" + id;
            } else {
                //id += "sz";
                id = "sz" + id;
            }
            return id;
        }).collect(Collectors.toList());
        System.out.println(newStockIds);
        // 3 配置请求头数据
        HttpHeaders headers = new HttpHeaders();
        headers.add("Referer", "https://finance.sina.com.cn/stock/");
        headers.add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36");
        // 组装请求对象
        HttpEntity<Object> entity = new HttpEntity<>(headers);
        /*
            4 由于存在多个code 而且每个code对应的信息量很大,所以采用分批查询的方法
         */
        Lists.partition(newStockIds, 20).forEach(list -> {
            // 原先是同步执行,效率太低 一次循环执行结束才能执行下一次循环
            // 引入线程池 异步执行任务
            threadPoolTaskExecutor.execute(() -> {
                // 5 组装动态url
                String url = stockInfoConfig.getMarketUrl() + String.join(",", list);
                // 6 发送请求
                String result = restTemplate.postForObject(url, entity, String.class);
            /*
                var hq_str_sz000001="平安银行,14.360,14.450,14.700,14.850,14.140,14.700,14.710,152880713,2222158762.020,512539,14.700,141700,14.690,532700,14.680,106200,14.670,163200,14.660,55900,14.710,15200,14.720,14100,14.730,135900,14.740,76100,14.750,2022-03-18,15:00:03,00";
                var hq_str_sz000002="万 科Ａ,16.440,16.680,17.450,17.550,16.300,17.450,17.460,183948423,3126922096.260,165005,17.450,236700,17.440,32600,17.430,9800,17.420,68500,17.410,133200,17.460,95500,17.470,295800,17.480,572000,17.490,466300,17.500,2022-03-18,15:00:03,00";
                var hq_str_sz000004="国华网安,19.190,19.300,19.750,19.900,19.060,19.750,19.760,3422600,66789709.000,4100,19.750,13500,19.740,4900,19.730,4000,19.720,3800,19.710,9900,19.760,10200,19.770,8300,19.780,3700,19.790,6500,19.800,2022-03-18,15:00:03,00";
             */
                // 7 解析数据
                List<StockRtInfo> resultList = parserStockInfoUtil.parser4StockOrMarketInfo(result, ParseType.ASHARE);
            /*
                "StockRtInfo(id=1505136634927009792, stockCode=000001, curTime=Fri Mar 18 15:00:00 GMT+08:00 2022, stockName=平安银行, openPrice=14.360, preClosePrice=14.450, curPrice=14.700, maxPrice=14.850, minPrice=14.140, tradeAmount=152880713, tradeVolume=2222158762.020)"
                "StockRtInfo(id=1505136634927009793, stockCode=000002, curTime=Fri Mar 18 15:00:00 GMT+08:00 2022, stockName=万 科Ａ, openPrice=16.440, preClosePrice=16.680, curPrice=17.450, maxPrice=17.550, minPrice=16.300, tradeAmount=183948423, tradeVolume=3126922096.260)"
             */
                System.out.println(resultList);
                // 8 批量插入数据库中 调用mapper层方法
                stockRtInfoMapper.insertBatch(resultList);
            });
        });
    }

    /*
       获取板块数据
     */
    @Override
    public void getBlockStock() {
        // 1 获取yml中配置的板块url地址
        String url = stockInfoConfig.getBlockUrl();
        // 2 发送请求
        String strResult = restTemplate.getForObject(url, String.class);
        //System.out.println("result = " + result);
        /*
            var S_Finance_bankuai_sinaindustry = {"new_blhy":"new_blhy,玻璃行业,19,16.31,0.31842105263158,1.9911795681938,413593244,4462878369,sh600293,10.029,3..........................}
         */
        // 3 上述结果需要解析 结果不是需要的类型
        List<StockBlockRtInfo> result = parserStockInfoUtil.parse4StockBlock(strResult);
        //System.out.println(result);
        /*
        {new_jjhy=new_jjhy,家具行业,16,14.215333333333,0.30866666666667,2.2195589645254,139054536,2576820458,sh603898,3.770,9.910,0.360,好莱客,
        new_gsgq=new_gsgq,供水供气,25,6.352,0.1232,1.9779090675572,410015901,2229295601,sh600758,10.112,3.920,0.360,辽宁能源,
        new_qczz=new_qczz,汽车制造,103,14.159702970297,-0.006039603960396,-0.042635279645498,1580908351,20567133192,sh600698,10.067,4.920,0.450,湖南天雁,
        new_blhy=new_blhy,玻璃行业,19,16.31,0.31842105263158,1.9911795681938,413593244,4462878369,sh600293,10.029,3.840,0.350,三峡新材,
        new_hqhy=new_hqhy,化纤行业,26,8.0884615384615,0.085,1.0620404632611,580570791,4702360962,sz002015,10.019,17.130,1.560,协鑫能科,
        new_jxhy=new_jxhy,机械行业,211,11.535853658537,0.061024390243902,0.53181087767925,3779014591,36153888029,sh600149,10.062,5.360,0.490,廊坊发展,
        .....
        }
        [StockBlockRtInfo(id=1505173624686952448, label=new_jjhy, blockName=家具行业, companyNum=16, avgPrice=14.215333333333, updownRate=2.2195589645254, tradeAmount=139054536, tradeVolume=2576820458, curTime=Sat Mar 19 21:25:00 GMT+08:00 2022),
        StockBlockRtInfo(id=1505173624686952449, label=new_gsgq, blockName=供水供气, companyNum=25, avgPrice=6.352, updownRate=1.9779090675572, tradeAmount=410015901, tradeVolume=2229295601, curTime=Sat Mar 19 21:25:00 GMT+08:00 2022),
        StockBlockRtInfo(id=1505173624691146752, label=new_qczz, blockName=汽车制造, companyNum=103, avgPrice=14.159702970297, updownRate=-0.042635279645498, tradeAmount=1580908351, tradeVolume=20567133192, curTime=Sat Mar 19 21:25:00 GMT+08:00 2022),
        StockBlockRtInfo(id=1505173624691146753, label=new_blhy, blockName=玻璃行业, companyNum=19, avgPrice=16.31, updownRate=1.9911795681938, tradeAmount=413593244, tradeVolume=4462878369, curTime=Sat Mar 19 21:25:00 GMT+08:00 2022),
        StockBlockRtInfo(id=1505173624691146754, label=new_hqhy, blockName=化纤行业, companyNum=26, avgPrice=8.0884615384615, updownRate=1.0620404632611, tradeAmount=580570791, tradeVolume=4702360962, curTime=Sat Mar 19 21:25:00 GMT+08:00 2022),
        ...........
         */
        // 4
        Lists.partition(result, 20).forEach(list -> {
            // 原先是同步执行,效率太低 一次循环执行结束才能执行下一次循环
            // 引入线程池 异步执行任务
            threadPoolTaskExecutor.execute(() -> {
                stockBlockRtInfoMapper.insertBatch(list);
            });
        });
    }

    /*
        拉取外盘数据功能
        外盘没有 交易量和交易额
     */
    @Override
    public void getOuterMarketInfo() {
        // 1 组装动态URL
        String url = stockInfoConfig.getMarketUrl() + String.join(",", stockInfoConfig.getOuter());
        // 2 设置请求头信息
        HttpHeaders headers = new HttpHeaders();
        headers.add("Referer","https://finance.sina.com.cn/stock/");
        // 下面这一行 可以不写
        headers.add("User-Agent","Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36");
        // 组装请求对象
        HttpEntity<Object> entity = new HttpEntity<>(headers);
        // 3 发起请求
        String result = restTemplate.postForObject(url, entity, String.class);
        System.out.println(result);
        String reg = "var hq_str_(.+)=\"(.+)\";";
        Pattern pattern = Pattern.compile(reg);
        // 将查询结果中匹配正则表达式的部分筛选出来
        Matcher matcher = pattern.matcher(result);
        // 4 收集大盘封装后的对象
        ArrayList<StockMarketIndexInfo> list = new ArrayList<>();
        // 5 对正则筛选的对象进行操作
        while (matcher.find()) {
            // 获取大盘的id
            String marketCode = matcher.group(1);
            // 其它信息 "xxxx" 其实就是保存的股票的所有信息 组成的字符串
            String other = matcher.group(2);
            String[] others = other.split(",");
            // 大盘名称
            String marketName = others[0];
            // 当前点
            BigDecimal curPoint = new BigDecimal(others[1]);
            // 涨跌值
            BigDecimal curPrice = new BigDecimal(others[2]);
            // 涨跌率
            BigDecimal upDownRate = new BigDecimal(others[3]);
            // 成交量
            //Long tradeAmount = Long.valueOf(others[4]);
            // 成交金额
            //Long tradeVol = Long.valueOf(others[5]);
            // 当前日期
            Date now = DateTimeUtil.getDateTimeWithoutSecond(DateTime.now()).toDate();
            // 封装数据
            StockMarketIndexInfo build = StockMarketIndexInfo.builder()
                    .id(idWorker.nextId() + "")
                    .markName(marketName)
                    .tradeVolume(0L)
                    .tradeAccount(0L)
                    .updownRate(upDownRate)
                    .curTime(now)
                    .curPoint(curPoint)
                    .currentPrice(curPrice)
                    .markId(marketCode)
                    .build();
            list.add(build);
        }
        log.info("集合内容：{}", list);//{} 是占位符
        //批量插入功能
        // 调用mapper层的方法
        stockMarketIndexInfoMapper.insertBatch(list);
    }
}
